let _vue = null

export default class VueRouter {
  static install (vue) {
    // 1.判断插件是否已经安装
    if (VueRouter.install.installed) {
      return
    }
    VueRouter.install.installed = true
    // 2.把vue的构造函数记录的全局变量中
    _vue = vue
    // 3.把创建vue实例时候传入的router对象注入的vue实例上
    // 混入，这里混入所有的vue实例都会有
    _vue.mixin({
      beforeCreate () {
        // 原型上挂在操作只需要执行一次，如果是组件不执行，如果是vue实例才执行
        if (this.$options.router) {
          _vue.prototype.$router = this.$options.router
        }
      }
    })
  }

  constructor (options) {
    this.options = options
    this.data = _vue.observable({
      current: '/'
    })
    // 解析routes解析路由规则,键值对形式
    this.routeMap = {}
    this.init()
  }

  // 封装初始化的一些方法
  init () {
    // 调用保存地址和组件映射的方法
    this.createRouteMap()
    // 调用创建router-link和router-view组件的方法
    this.initComponents()
    // 调用解决浏览器前进后退不重新加载组件的方法
    this.initEvent()
  }

  // 把构造函数中选项内传递过来的routes转换成键值对的形式,存储到routeMap中
  createRouteMap () {
    // 遍历routes把path和component存到routerMap对象中;
    this.options.routes.forEach((route) => {
      this.routeMap[route.path] = route.component
    })
  }

  // 创建组件
  initComponents () {
    // 创建router-link组件, 两个参数,1组件名, 2组件参数
    _vue.component('router-link', {
      props: {
        to: String
      },
      render (h) {
        // 第一个参数选择器，第二个参数设置的属性, 第三个参数设置子元素
        return h('a', {
          // 添加dom对象的属性写在attrs中
          attrs: {
            href: this.to
          },
          // 注册dom对象的事件
          on: {
            click: this.clickHandler
          }
        }, [this.$slots.default]) // 获取子元素默认插槽
      },
      methods: {
        // 事件处理函数
        clickHandler (e) {
          // 1.调用pushState方法改变浏览器的地址,pushState接收三个参数
          // 1.触发pushState传给事件对象的参数,2. 网页标题 3. 地址
          history.pushState({}, '', this.to)
          // 设置路由地址,之后才能根据这个地址加载对应的组件(这里的this是vue实例)
          // 因为这个属性是响应式的所以当这个属性值改变时会重新加载组件,(走下面的router-view组件)并时时渲染试图
          this.$router.data.current = this.to
          e.preventDefault()
        }
      }
      // 运行时版本不支持template，只支持render函数
      // template: '<a :href="to"><slot></slot></a>'
    })
    // 创建router-view组件
    const self = this
    _vue.component('router-view', {
      // 利用h参数创建虚拟dom
      render (h) {
        // 获取当前路由地址(data.current)之后值是在router-link组件内设置的 找到对应的组件
        const component = self.routeMap[self.data.current]
        // h函数可以接收一个组件转换成一个虚拟dom
        return h(component)
      }
    })
  }

  // 解决浏览器前进后退不重新加载组件的方法
  initEvent () {
    window.addEventListener('popstate', () => {
      // 将响应式的保存路径的值设置成浏览器地址中路径部分的值即可
      this.data.current = window.location.pathname
    })
  }
}
